﻿/********************************************************************************
* Copyright 2010 Zane Thorn (zane.thorn@gmail.com)                              *
*                                                                               *
* NeturalMath is free software: you can redistribute it and/or modify           *
* it under the terms of the GNU Lesser General Public License as published by   *
* the Free Software Foundation, either version 3 of the License, or             *
* (at your option) any later version.                                           *
*                                                                               *
* NeturalMath is distributed in the hope that it will be useful,                *
* but WITHOUT ANY WARRANTY; without even the implied warranty of                *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                 *
* GNU Lesser General Public License for more details.                           *
*                                                                               *
* You should have received a copy of the GNU Lesser General Public License      *
* along with NeturalMath.  If not, see <http://www.gnu.org/licenses/>.          *
********************************************************************************/

using System;

namespace NeturalMath
{
    /// <summary>
    /// The data type used internally by Netural Math to represent a numeric value
    /// </summary>
    public class NumberValue:MathValue
    {
        internal NumberValue(double value,MathRuntime runtime)
            : base(ValueTypes.Number, "number", value,runtime)
        {
            Value = value;
        }

        internal NumberValue(ValueTypes type,string typeName,double value,MathRuntime runtime)
            :base(type,typeName,value,runtime)
        {
            Value = value;
        }

        /// <summary>
        /// Overrides the base variable with the specified value
        /// </summary>
        public new double Value { get; private set; }

        #region Basic Math Functions

        /// <summary>
        /// Overrides basic Add functionality.
        /// </summary>
        /// <param name="arg">The value to be added</param>
        /// <returns>The Sum of the two values</returns>
        protected override MathValue Add(MathValue arg)
        {
            var other = (NumberValue)arg;
            return Runtime.NewNumber(this.Value + other.Value);
        }

        /// <summary>
        /// Overrides basic Subtract functionality.
        /// </summary>
        /// <param name="arg">The value to be subtracted</param>
        /// <returns>The difference between the two values</returns>
        protected override MathValue Subtract(MathValue arg)
        {
            var other = (NumberValue)arg;
            return Runtime.NewNumber(this.Value - other.Value);
        }

        /// <summary>
        /// Overrides basic Multiply functionality.
        /// </summary>
        /// <param name="arg">The value to be multiplied</param>
        /// <returns>The product between the two values</returns>
        protected override MathValue Multiply(MathValue arg)
        {
            var other = (NumberValue)arg;
            return Runtime.NewNumber(this.Value * other.Value);
        }

        /// <summary>
        /// Overrides basic Divide functionality.
        /// </summary>
        /// <param name="arg">The value to be divided by</param>
        /// <returns>The dividand between the two values</returns>
        protected override MathValue Divide(MathValue arg)
        {
            var other = (NumberValue)arg;
            return Runtime.NewNumber(this.Value / other.Value);
        }

        /// <summary>
        /// Overrides basic Modulo functionality.
        /// </summary>
        /// <param name="arg">The value to be divided by</param>
        /// <returns>The remainder between the two values</returns>
        protected override MathValue Modulo(MathValue arg)
        {
            var other = (NumberValue)arg;
            return Runtime.NewNumber(this.Value % other.Value);
        }

        /// <summary>
        /// Overrides basic Power functionality.
        /// </summary>
        /// <param name="arg">The value to be raised by</param>
        /// <returns>The exponent of the two values</returns>
        protected override MathValue Power(MathValue arg)
        {
            var other = (NumberValue)arg;
            return Runtime.NewNumber(Math.Pow(this.Value, other.Value));
        }

        #endregion

        #region Comparision Functions

        ///// <summary>
        ///// Overrides base not equals function
        ///// </summary>
        ///// <param name="arg"></param>
        ///// <returns></returns>
        //protected override MathValue IsNotEqual(MathValue arg)
        //{
        //    return Value.Equals(arg.Value) ? False : True;
        //}

        #endregion

        #region Conversion Functions

        /// <summary>
        /// Flips the bits in the number and returns a new number value
        /// </summary>
        /// <returns>The flipped form of the number</returns>
        protected override MathValue Flip()
        {
            return Runtime.NewNumber(Value.Flip());
        }

        /// <summary>
        /// Converts the provided value into a StringValue
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        protected override MathValue ConvertToNativeValue(MathValue value)
        {
            return value.ConvertToNumber();
        }

        /// <summary>
        /// Converts the current value to a string
        /// </summary>
        /// <returns>A string representation of the value</returns>
        protected internal override MathValue ConvertToString()
        {
            if (double.IsNaN(Value))
                return Runtime.UndefinedString;

            if (double.IsPositiveInfinity(Value))
                return Runtime.InfinityString;

            if (double.IsNegativeInfinity(Value))
                return Runtime.NegativeInfinityString;

            return Runtime.NewString(Value.ToString());
        }

        /// <summary>
        /// Converts the value to a number
        /// </summary>
        /// <returns>The numeric data for the value</returns>
        protected internal override MathValue ConvertToNumber()
        {
            return this;
        }

        /// <summary>
        /// Converts the value to a boolean
        /// </summary>
        /// <returns></returns>
        protected internal override MathValue ConvertToBoolean()
        {
            if (Value == 0 || double.IsNaN(Value))
                return Runtime.False;
            return Runtime.True;
        }

        /// <summary>
        /// Converts the value to a range
        /// </summary>
        /// <returns></returns>
        protected internal override MathValue ConvertToRange()
        {
            return Runtime.NewRange(Value, Value);
        }

        /// <summary>
        /// Converts the value to a complex
        /// </summary>
        /// <returns></returns>
        protected internal override MathValue ConvertToComplex()
        {
            return Runtime.NewComplex(Value, 0);
        }

        /// <summary>
        /// Converts the value to a unit, based on the specified unit measure
        /// </summary>
        /// <param name="measure"></param>
        /// <returns></returns>
        protected internal override MathValue ConvertToUnit(Units.UnitMeasure measure)
        {
            return Runtime.NewUnit(Value, measure);
        }

        #endregion

        /// <summary>
        /// Returns the string representation of the value
        /// </summary>
        /// <returns></returns>
        protected override string GetToString()
        {
            return Value.ToString();
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="arg"></param>
        /// <returns></returns>
        protected override MathValue And(MathValue arg)
        {
            var other = (NumberValue)arg;
            return Runtime.NewNumber(this.Value.And( other.Value));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="arg"></param>
        /// <returns></returns>
        protected override MathValue Or(MathValue arg)
        {
            var other = (NumberValue)arg;
            return Runtime.NewNumber(this.Value.Or(other.Value));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="arg"></param>
        /// <returns></returns>
        protected override MathValue Xor(MathValue arg)
        {
            var other = (NumberValue)arg;
            return Runtime.NewNumber(this.Value.Xor(other.Value));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        protected override bool IsTrue()
        {
            return Value != 0.0;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        protected override MathValue ToMinus()
        {
            return Runtime.NewNumber(-Value);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="arg"></param>
        /// <returns></returns>
        protected override bool? IsLessThan(MathValue arg)
        {
            var other = (double)arg.Value;
            return Value < other;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="arg"></param>
        /// <returns></returns>
        protected override bool? IsGreaterThan(MathValue arg)
        {
            var other = (double)arg.Value;
            return Value > other;
        }

        
    }
}
